package com.hxw.sample.opengl30;

import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;

import com.hxw.sample.opengl30.uitls.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * 实现EBO:又名IBO，元素缓冲对象，用于存储顶点索引值
 * 减少CPU到GPU数据的传输，不用每次都执行glVertexAttribPointer进行传参
 * 提高渲染效率，数据存在GPU，可重复使用，可以在GPU对数据进行转换，减少CPU负载
 *
 * 该案例为在EBO绘制四边形的基础上修改，表现GLES中如何进行条件判断
 * 这里利用两个三角形渲染不同的颜色，来体现条件判断的生效
 *
 */
public class TriangleRenderV4_EBO_V3 implements GLSurfaceView.Renderer {

    //顶点绘制脚本
    private static final String vertex_shader = "attribute vec4 vPosition;" +//顶点坐标，我们需要在Java获取到这个值并赋值
            "varying vec4 vColor;"+
            "attribute float aIndex;"+
            "void main() {" +
            "  gl_Position = vPosition;" +//gl_Position是OpenGL内部变量，OpenGL通过该值获取顶点位置
            "  if(aIndex < 0.5){" +
            "    vColor = vec4(0.0,1.0,0.0,1.0);"+
            "  }else{" +
            "    vColor = vec4(1.0,1.0,0.0,1.0);"+
            "  }"+
            "}";

    //纹理绘制脚本（在顶点的基础上，加上颜色或图像就是纹理）
    private static final String fragment_shader = "precision mediump float;//浮点数精度\n" +
            "varying vec4 vColor;\n" +//只要在vertex_shader中修改了，这边也会同步
            "void main() {\n" +
            "    gl_FragColor = vColor;\n" +//gl_FragColor是OpenGL内部变量，OpenGL通过该值获取像素点的纹理
            "}";

    //一个顶点通常用x,y,z这三个值来表示，但如果是二维，则z可有可无，为0即可
    private final float[] VERTEX ={
            -1f, 0f , 0f,0,//第四个值来决定颜色
            0f ,-1f , 0f,0,
            0f , 1f , 0f,0,
            0f ,-1f , 0f,0.5f,
            0f , 1f , 0f,0.5f,
            1f , 0f , 0f,0.5f,
    };
    private FloatBuffer mVertexBuffer;

    private int mProgram,mPositionHandle,mIndexHandle;

    private final int[] vboIds = new int[1];//VBO
    private final int[] eboIds = new int[1];//EB0
    private final int[] indics = {0,1,2,3,4,5};

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        final int vertexLen = VERTEX.length*4;//字节长度,float占4个字节，所以乘以4
        mVertexBuffer = ByteBuffer.allocateDirect(vertexLen)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(VERTEX);
        mVertexBuffer.position(0);

        int idxLen = indics.length*4;
        IntBuffer idxBuffer = ByteBuffer.allocateDirect(idxLen)
                .order(ByteOrder.nativeOrder())
                .asIntBuffer();
        idxBuffer.put(indics);
        idxBuffer.position(0);

        //程序必须在onSurfaceCreated之后加载才行，否则OpenGL环境未就绪是无法正常加载的
        mProgram = ShaderUtil.createProgram(vertex_shader,fragment_shader);

        if (mProgram != 0){
            mPositionHandle = GLES30.glGetAttribLocation(mProgram,"vPosition");//获取顶点脚本中的vPosition变量的句柄
            mIndexHandle =  GLES30.glGetAttribLocation(mProgram,"aIndex");

            //生成VBO
            GLES30.glGenBuffers(1,vboIds,0);//第一个参数为需要创建的VBO数量，第三个参数为偏移量，一般为0
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,vboIds[0]);//绑定VBO
            GLES30.glBufferData(GLES20.GL_ARRAY_BUFFER,vertexLen,mVertexBuffer,GLES30.GL_STATIC_DRAW);//将数据写入VBO
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);//解绑VBO

            //生成VBO
            GLES30.glGenBuffers(1,eboIds,0);//第一个参数为需要创建的EBO数量，第三个参数为偏移量，一般为0
            GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,eboIds[0]);//绑定EBO
            GLES30.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,idxLen,idxBuffer,GLES30.GL_STATIC_DRAW);//将数据写入EBO
            GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);//解绑EBO
        }

        GLES30.glClearColor(1,0,0,1f);//设置清空View时的背景色
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0,0,width,height);//绘制的区间
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);//清除颜色缓冲区

        GLES30.glUseProgram(mProgram);//指定当前渲染操作所要使用的着色器程序

        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,vboIds[0]);//绑定VBO
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,eboIds[0]);//绑定VBO

        GLES30.glEnableVertexAttribArray(mPositionHandle);//设置参数为可用
        GLES30.glVertexAttribPointer(mPositionHandle, 3, GLES30.GL_FLOAT, false, 16, 0);

        GLES30.glEnableVertexAttribArray(mIndexHandle);//设置参数为可用
        GLES30.glVertexAttribPointer(mIndexHandle, 1, GLES30.GL_FLOAT, false, 16, 12);

        GLES30.glDrawElements(GLES30.GL_TRIANGLES,indics.length,GLES30.GL_UNSIGNED_INT,0);//采用EBO渲染
        //第二个参数为顶点数量，第三个参数为EBO的数据类型：int，第四个参数为偏移量

        GLES30.glDisableVertexAttribArray(mPositionHandle);//释放句柄
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);//解绑VBO
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);//解绑EBO
    }

    public void onDestroy(){
        GLES30.glDeleteBuffers(1,vboIds,0);
        GLES30.glDeleteBuffers(1,eboIds,0);
        GLES30.glDeleteProgram(mProgram);
    }
}
